/*
 * GClubLeagueHistoryRecord.java
 * Created on 2 févr. 08
 *
 * Glacéo Internet Platform
 * http://sourceforge.net/projects/chm/
 *
 * Copyright (c) 2005-2009, Jens and Jan Janke (VirtualHockey Project)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hockeo.vhbase.data.dao.club;


import java.math.BigDecimal;
import java.math.RoundingMode;

import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

import com.hockeo.vhbase.data.dao.IGEntity;
import com.hockeo.vhbase.data.dao.contest.GContest;
import com.hockeo.vhbase.data.dao.standings.GArchivedStandings;
import com.hockeo.vhbase.data.dao.standings.GECRStandings;
import com.hockeo.vhbase.data.dao.standings.GENRStandings;
import com.hockeo.vhbase.data.helper.GArchivedStandingsType;
import com.hockeo.vhbase.data.helper.GClubMultiRoundContestStatus;
import com.hockeo.vhbase.data.helper.GContestRoundType;
import com.hockeo.vhbase.data.helper.GMatchResult;
import com.hockeo.vhbase.data.helper.GStandingsRankType;

/**
 * Records a club's results during a normal national league season.
 *
 * @version $Id$
 * @author jjanke
 */
@Entity
@DiscriminatorValue( "LEAGUE" )
public class GClubLeagueHistoryRecord extends GClubHistoryRecord
{
  @ManyToOne( fetch = FetchType.LAZY )
  @JoinColumn( name = "nl_standings_id" )
  private GArchivedStandings d_standings;

  @Column( name = "nl_promoted" )
  private boolean            d_fPromoted     = false;

  @Column( name = "nl_relegated" )
  private boolean            d_fRelegated    = false;

  @Column( name = "nl_qualified_eu1" )
  private boolean            d_fQualifiedEU1 = false;

  @Column( name = "nl_qualified_eu2" )
  private boolean            d_fQualifiedEU2 = false;

  /** Default parameterless constructor. */
  protected GClubLeagueHistoryRecord()
  {}

  /**
   * Creates a new club/league/season history record.
   *
   * @param standings the archived standings for the season for which to create a history
   *          record
   */
  public GClubLeagueHistoryRecord( GArchivedStandings standings )
  {
    super( standings.getSeason(), standings.getClub(), standings.getContestElement().getContestRound().getContest() );

    if ( standings.getArchiveType() != GArchivedStandingsType.END_OF_SEASON )
      throw new IllegalArgumentException( "The standings no. " + standings.getId() + " have the wrong archive type: "
          + standings.getArchiveType().name() );

    d_standings = standings;

    setRank( standings.getRank() );
    setReachedRound( GContestRoundType.ROUND_MAIN );
    setNumLosses( standings.getNumLosses() );
    setNumLossesOT( standings.getNumLossesOT() );
    setNumMatches( standings.getNumMatches() );
    setNumWins( standings.getNumWins() );
    setNumWinsOT( standings.getNumWinsOT() );
    setNumPoints( standings.getNumPoints() );
    setPointsPercentage( standings.getPointsPercentage() );
    setPointsPerMatchAvg( standings.getPointsPerMatchAvg() );

    // ECR points
    //
    updateECRPoints();

    // Intl. cup qualification
    //
    if ( getContest().getCategory() == 1 )
    {
      d_fQualifiedEU1 = ( standings.getRankType() == GStandingsRankType.QUALIFIED_EU1 );
      d_fQualifiedEU2 = ( standings.getRankType() == GStandingsRankType.QUALIFIED_EU2 );
    }
    // Promotion
    //
    else
      d_fPromoted = ( standings.getRankType() == GStandingsRankType.PROMOTED_1 );

    // Relegation
    //
    d_fRelegated = ( standings.getRankType() == GStandingsRankType.RELEGATED );
  }

  @Override
  public GClubMultiRoundContestStatus getMultiRoundContestStatus()
  {
    return GClubMultiRoundContestStatus.REACHED_LAST_ROUND;
  }

  @Override
  public void updateECRStandings( GECRStandings ecr )
  {
    ecr.setPointsS1League( getPointsECR() );
  }

  @Override
  public void updateENRStandings( GENRStandings enr )
  {
  // ENR points are not obtained during a national league contest
  }

  public GArchivedStandings getStandings()
  {
    return d_standings;
  }

  public boolean isPromoted()
  {
    return d_fPromoted;
  }

  public boolean isRelegated()
  {
    return d_fRelegated;
  }

  public boolean isQualifiedEU1()
  {
    return d_fQualifiedEU1;
  }

  public boolean isQualifiedEU2()
  {
    return d_fQualifiedEU2;
  }

  /**
   * <p>
   * Calculates the current ECR point value based on the number of played rounds, matches,
   * reached points etc. and sets the calculated value to the super class using the method
   * {@link #setPointsECR(BigDecimal)}.
   * </p>
   *
   * <p>
   * ECR points for a league competition are calculated as follows:
   * </p>
   *
   * <ol>
   * <li>The number of points obtained during the league contest is determined and for the
   * first three teams bonus points are added. These bonus points correspond to 10% of the
   * maximum possible amount of points for the 1st, to 6% for the 2nd and to 3% for the
   * 3rd.</li>
   * <li>The number of points (incl. the bonus points) is then divided by the maximum
   * possible amount of points (number of matches multiplied by 3). The bonus points are
   * not counted in the maximum possible amount of points. If the result is greater than 1
   * (possible due to bonus points), the result is cut down to 1.</li>
   * <li>The quotient (reached/possible points) is then multiplied by the league
   * coefficient and the result corresponds to the ECR points awarded for one league
   * season.</li>
   * </ol>
   */
  private void updateECRPoints()
  {
    GContest contest = d_standings.getContestElement().getContestRound().getContest();
    BigDecimal decPoints = BigDecimal.valueOf( d_standings.getNumPoints() );
    BigDecimal decMaxPoints = BigDecimal.valueOf( d_standings.getNumMatches() * GMatchResult.VICTORY.getNumPoints() );

    switch ( d_standings.getRank() )
    {
      case 1:
        decPoints = decPoints.add( decMaxPoints.multiply( BigDecimal.valueOf( 0.10 ) ) );
        break;

      case 2:
        decPoints = decPoints.add( decMaxPoints.multiply( BigDecimal.valueOf( 0.06 ) ) );
        break;
      case 3:

        decPoints = decPoints.add( decMaxPoints.multiply( BigDecimal.valueOf( 0.03 ) ) );
        break;

      default:
        break;
    }

    BigDecimal decPct = decPoints.divide( decMaxPoints, 4, RoundingMode.HALF_UP );

    if ( decPct.compareTo( BigDecimal.ONE ) > 0 )
      decPct = BigDecimal.ONE;

    setPointsECR( decPct.multiply( contest.getRankingCoefficient() ).setScale( 2, RoundingMode.HALF_UP ) );
  }

  public Class<? extends IGEntity> getGEntityClass()
  {
    return GClubLeagueHistoryRecord.class;
  }
}
